// 判断是否是对象
const isObject = val => typeof val === 'object' && val !== null
// 转换为响应式对象
const convert = target => (isObject(target) ? reactive(target) : target)
//
// const hasOwnProperty = Object.prototype.hasOwnProperty
//
// const hasOwn = (obj, key) => hasOwnProperty.call(obj, key)

/**
 * @description 创建响应式数据
 * @param {Object} target 对象
 * @return {Object} 响应式对象
 */
export function reactive(target) {
  if (!isObject(target)) {
    throw new Error('reactivity: target must be an object')
  }
  const handler = {
    get(target, key, receiver) {
      // 收集依赖
      track(target, key)
      // 转换为响应式对象
      return convert(Reflect.get(target, key, receiver))
    },
    set(target, key, value, receiver) {
      let result = true
      // 值变化的时候进行更新
      if (Reflect.get(target, key, receiver) !== value) {
        result = Reflect.set(target, key, value, receiver)
        // 触发更新
        update(target, key)
      }
      return result
    },
    deleteProperty(target, key) {
      if (!(key in target)) return false
      // 触发更新
      update(target, key)
      return Reflect.deleteProperty(target, key)
    },
  }
  return new Proxy(target, handler)
}

// 当前活动的 effect 函数
let activeEffect = null

export function effect(callback) {
  activeEffect = callback
  // 访问响应式对象属性，去收集依赖
  callback()
  activeEffect = null
}

let targetMap = new WeakMap()

// 收集依赖
export function track(target, key) {
  if (!activeEffect) return
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    depsMap = new Map()
    targetMap.set(target, depsMap)
  }
  let deps = depsMap.get(key)
  if (!deps) {
    deps = new Set()
    depsMap.set(key, deps)
  }
  deps.add(activeEffect)
}

// 更新
export function update(target, key) {
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  const deps = depsMap.get(key)
  if (!deps) return
  deps.forEach(dep => dep())
}

// 调用 reactive 创建响应式对象
export function ref(raw) {
  // 判断 raw 是否是响应式对象
  if (isObject(raw) && raw.__isReactive) {
    return raw
  }
  // 创建响应式对象
  let value = convert(raw)
  const r = {
    __isReactive: true,
    get value() {
      track(r, 'value')
      return value
    },
    set value(newValue) {
      if (value === newValue) return
      update(r, 'value')
      value = newValue
    },
  }
  return r
}

// 接受一个 reactive 响应式对象，返回一个响应式对象
export function toRefs(proxy) {
  const result = proxy instanceof Array ? new Array(proxy.length) : {}
  for (let key in proxy) {
    result[key] = ref(proxy[key])
  }
  return result
}

// 接受一个有返回值的函数,监听该函数内部响应式数据的变化,最后返回该函数的返回值
export function computed(getter) {
  const result = ref()
  effect(() => {
    result.value = getter()
  })
  return result
}
